home *** CD-ROM | disk | FTP | other *** search
/ BBS Toolkit / BBS Toolkit.iso / windows / xmdmdlp.zip / XMODEM.C < prev    next >
C/C++ Source or Header  |  1992-07-10  |  26KB  |  869 lines

  1. /************************************************************************/
  2. /*                                                                      */
  3. /* XMODEM.DLP                                                           */
  4. /*                                                                      */
  5. /* This is a sample (DLP) DLL to implement the XMODEM protocol          */
  6. /*                                                                      */
  7. /* Four calls are made to the (DLP) by PW.EXE                           */
  8. /*   GET_DLL_CAPS( LPSTR )                                              */
  9. /*   ADVANCED_DLL( PROTOSET FAR *, MAIN FAR *, HWND, LPSTR )            */
  10. /*   STARTDLL_XFER( PROTOSET FAR *, MAIN FAR *, HWND, LPSTR, int, int ) */
  11. /*   DLL_XFER( PROTOSET FAR *, MAIN FAR *, HWND, LPSTR, int )           */
  12. /*                                                                      */
  13. /*  PROTOSET is a struct of PW.EXE variables which the protocol can     */
  14. /*           use. It also contains callback fuctions for all the        */
  15. /*         communication functions necessary to implement a             */
  16. /*         protocol. A large global buffer is already allocated         */
  17. /*         (10240 bytes) and pd->bigptr is a locked pointer to this     */
  18. /*         memory.  66 extra bytes are contained in the struct to       */
  19. /*         be cast and used by the (DLP) as required. Reference         */
  20. /*         XMODEM.H.  The (DLP) should use this area for any global     */
  21. /*           variables it requires, thus supporting mulitple instances  */
  22. /*         use of the protocol.                                         */
  23. /*                                                                      */
  24. /*  MAINSET  is a struct of PW.EXE variables of a more general nature   */
  25. /*         which the protocol can use. Reference XMODEM.H.              */
  26. /*                                                                      */
  27. /*   ADVANCED_DLL, STARTDLL_XFER, & DLL_XFER are all passed a LPSTR to  */
  28. /*          3 bytes of exta data which is intended to be used for       */
  29. /*      advanced  settings.                                             */
  30. /*                                                                      */
  31. /*   Note:   To allow aspect to determine sucess or failure of the      */
  32. /*          protocol *(pd->aspfxfer) should be set to equal to          */
  33. /*      ASP_PROT_FAIL on entry and set to ASP_PROT_SUCCESS on           */
  34. /*      termination if successful.                                      */
  35. /*                                                                      */
  36. /************************************************************************/
  37. /************************************************************************/
  38. /*                                                                      */
  39. /* This sample is provided as a service to you.  DATASTORM does not in  */
  40. /* any way warrant the source code, nor do we commit to any support on  */
  41. /* this sample file.                                                    */
  42. /*                                                                      */
  43. /************************************************************************/
  44.  
  45. #define _WINDOWS
  46. #define _WINDLL
  47. #include <windows.h>
  48. #include <string.h>
  49. #include <io.h>
  50. #include <dos.h>
  51. #include "xmodem.h"
  52.  
  53. //▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
  54. //▓▓
  55. //▓▓ global variables used by xmodem.dlp
  56. //▓▓
  57. //▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
  58. char szBuffer[128];
  59. PROTOSET FAR *pd;
  60. MAIN FAR *mn;
  61. HWND hWnd;
  62. HANDLE hInst;
  63. ADVANCEDSET adv;
  64.  
  65.  
  66. //▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
  67. //▓▓
  68. //▓▓ 1. DLL entry and exit routines
  69. //▓▓
  70. //▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
  71. //--------------------------------------------------------------------------
  72. //
  73. // LibMain() - DLL entry function
  74. //
  75. //--------------------------------------------------------------------------
  76. BOOL FAR PASCAL LibMain(hInstance, wDataSeg, cbHeapSize, lpszCmdLine)
  77. HANDLE hInstance;
  78. WORD wDataSeg;
  79. WORD cbHeapSize;
  80. LPSTR lpszCmdLine;
  81. {
  82.     hInst = hInstance;               // save instance handle for dialog box and resources
  83.     if(cbHeapSize !=0 )
  84.         UnlockData(0);
  85.     return(1);
  86. }
  87.  
  88. //--------------------------------------------------------------------------
  89. //
  90. // WEP() - DLL termination function
  91. //
  92. //    Notes:  1. WEP may not be called when the DLL closes and therefore
  93. //            cannot be counted on to perform termination tasks.
  94. //
  95. //--------------------------------------------------------------------------
  96. void FAR PASCAL WEP(nParamater)
  97. int nParamater;
  98. {
  99.     return;
  100. }
  101.  
  102.  
  103.  
  104.  
  105.  
  106.  
  107.  
  108.  
  109.  
  110.  
  111. /**********************************************************************/
  112. /*                                                                                             */
  113. /* GET_DLL_CAPS                                                                         */
  114. /*                                                                                          */
  115. /* This procedure is called by PW.EXE when a new (DLP) file is          */
  116. /* found in the PW.EXE directory.  The (DLP) is to return the             */
  117. /* bitflags of its capablities.                                                     */
  118. /*                                                                                          */
  119. /* DLL_CAP_SHOWXFER-requests PW.EXE to show its normal xfer dlg box     */
  120. /* DLL_CAP_MULTISEND-(DLP) is capable of sending multiple files         */
  121. /* DLL_CAP_AUTODOWNLOAD-(DLP) is capable of autodowloading files         */
  122. /* DLL_CAP_PWOPENFILE-requests PW.EXE to open the inital file             */
  123. /* DLL_CAP_RCVNEEDNAME-PW.EXE is to prompt user for a rcv file name     */
  124. /* DLL_CAP_ADVANCED-(DLP) has advanced dialog box for user setup         */
  125. /*                                                                                          */
  126. /* If (DLP) return DLL_CAP_AUTODOWNLOAD, then the auto detect string  */
  127. /*     (null terminated, 11 char max.) should be copied to lptr          */
  128. /*     passed into the function.                                                     */
  129. /*                                                                                             */
  130. /**********************************************************************/
  131. WORD FAR PASCAL GET_DLL_CAPS( lptr )
  132. LPSTR lptr;
  133. {
  134. WORD i = 0;
  135.    return( i | DLL_CAP_ADVANCED | DLL_CAP_RCVNEEDNAME );
  136. //    lstrcpy( lptr,"0x1b0x1b");                                     // if autodownload capable
  137. //    return( i | DLL_CAP_AUTODOWNLOAD | DLL_CAP_ADVANCED | DLL_CAP_RCVNEEDNAME );
  138. }
  139.  
  140. /**********************************************************************/
  141. /*                                                                                             */
  142. /* ADVANCED_DLL                                                                         */
  143. /*                                                                                          */
  144. /* This procedure is called by PW.EXE when the (DLP) has return the     */
  145. /* DLL_CAP_ADVANCED capablity flag and the user has selected the         */
  146. /* advanced menu (or dblclicked on the protocol button).                  */
  147. /* it is intened to allow the (DLP) to provide a Dialog box for          */
  148. /* advanced options.                                                  */
  149. /*                                                                                           */
  150. /* Note:      This is a dummy routine, for example only                    */
  151. /*                                                                                           */
  152. /**********************************************************************/
  153. void FAR PASCAL ADVANCED_DLL( inpd, inmn, hwnd, extra )
  154. PROTOSET FAR *inpd;
  155. MAIN FAR *inmn;
  156. HWND hwnd;                             // handle to the parent window, for dialog box
  157. LPSTR extra;                           // 3 Bytes of information for advanced setup
  158. {
  159. FARPROC lpproc;
  160.  
  161.     adv = *(ADVANCEDSET FAR *)extra;
  162.     lpproc = MakeProcInstance(SetupDlgProc, hInst );
  163.     DialogBox(hInst,"SETUP",hwnd,lpproc );
  164.     FreeProcInstance( lpproc );
  165.     *(ADVANCEDSET FAR *)extra = adv;
  166. }
  167.  
  168. /**********************************************************************/
  169. /*                                                                                             */
  170. /* STARTDLL_XFER                                                                         */
  171. /*                                                                                          */
  172. /* Allows (DLP) to initialize variables and start the actual xfer.      */
  173. /*     send = TRUE if sendin a file, FALSE receiving a file              */
  174. /*     from_auto = TRUE if called from auto detect sequence              */
  175. /**********************************************************************/
  176. int FAR PASCAL STARTDLL_XFER( inpd, inmn, hwnd, extra, send, from_auto)
  177. PROTOSET FAR *inpd;
  178. MAIN FAR *inmn;
  179. HWND hwnd;
  180. LPSTR extra;
  181. int send;
  182. int from_auto;
  183. {
  184.  
  185.     pd = inpd;
  186.     mn = inmn;
  187.  
  188. //    if(from_auto)                             // if auto detect the initialize
  189. //    {
  190. //        lstrcpy( pd->szTempDir,"d:\\pw");
  191. //        lstrcpy( pd->szTempName,"temp.gif");
  192. //    }
  193.  
  194.     if(!FileRxTX(send, pd->szTempName ))
  195.     {
  196.           (*pd->EndXfer)();
  197.           return(FALSE);
  198.     }
  199. // Init. global varables ---------------------------------------------------
  200.     pd->rec_len        =  128;
  201.     pd->xcount         =  132;
  202.     pd->datalen        =  0;
  203.     pd->Aborting       =  0;
  204.     pd->no_char_wait     =  1000;
  205.     pd->retries        =  3;
  206.     pd->runcnt         =  0;
  207.     pd->xcount         =  0;
  208. // -------------------------------------------------------------------------
  209.     if(pd->bdiag)                              // if requested show xfer box, ASPECT can request this to be FALSE
  210.     {
  211.         (*pd->ShowXferBox)(send);              // Call PW.EXE function to show xfer box
  212.         SetWindowText( pd->hDlg1,"DLL [XModem]");
  213.     }
  214.     if(send)
  215.     {
  216.         pd->pcstate     = IDX_WAITACK;          // set state to show we are sending
  217.         pd->bbegin         = 1;
  218.         pd->end_record = 255;
  219.     }
  220.     else                                        // receiving
  221.     {
  222.         pd->pcstate     = IDX_RXING;            // set state to show we are receiving
  223.         pd->bbegin         = 2;
  224.         pd->rec_no         = 1;                    // initialize record count
  225.         pd->end_record = 0;
  226.         pd->xwaittime     = GetTickCount()+10000; // set timout to 10 seconds
  227.         (*pd->WriteCommW) ( (HANDLE)mn->hCid,(LPSTR)"\x15",(int)1);          // start with NACK
  228.     }
  229.     return(TRUE);
  230. }
  231.  
  232. /**********************************************************************/
  233. /*                                                                                             */
  234. /* DLL_XFER                                                                                */
  235. /*                                                                                          */
  236. /* Called every timer tick (~55msecs)                                  */
  237. /**********************************************************************/
  238. int  FAR PASCAL DLL_XFER(inpd, inmn, hwnd, extra, send)
  239. PROTOSET FAR *inpd;
  240. MAIN FAR *inmn;
  241. HWND hwnd;
  242. LPSTR extra;
  243. int send;
  244. {
  245.     pd = inpd;
  246.     mn = inmn;
  247.  
  248.     switch(pd->pcstate)           // switch on xfer state
  249.     {
  250.         case IDX_RXING:
  251.             RXING();
  252.             break;
  253.         case IDX_NOCHAR:
  254.             NOCHAR();
  255.             break;
  256.         case IDX_WAITACK:
  257.             WAITACK();
  258.             break;
  259.     }
  260.     return(TRUE);
  261. }
  262.  
  263.  
  264.  
  265.  
  266.  
  267.  
  268.  
  269.  
  270.  
  271.  
  272.  
  273. //▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓
  274. //█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█
  275. //▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓
  276. //█▓█▓                                                                   ▓█▓█
  277. //▓█▓█                                                                   █▓█▓
  278. //█▓█▓                   L O C A L     R O U T I N E S                   ▓█▓█
  279. //▓█▓█                                                                   █▓█▓
  280. //█▓█▓                                                                   ▓█▓█
  281. //▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓
  282. //█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█
  283. //▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓█▓
  284. BOOL FAR PASCAL SetupDlgProc( hDlg, message, wParam, lParam )
  285. HWND hDlg;
  286. WORD message;
  287. WORD wParam;
  288. LONG lParam;
  289. {
  290.  
  291.     switch (message)
  292.     {
  293.         case WM_INITDIALOG:
  294.             CheckDlgButton( hDlg, 10, (adv.fRcvFileSelect?0:1));
  295.             CheckDlgButton( hDlg, 11, (adv.fSendFileSelect?0:1));
  296.             CheckRadioButton( hDlg, 20, 21, 20+(adv.fChecksum?1:0));
  297.             CheckRadioButton( hDlg, 30, 31, 30+(adv.fRecLength128?1:0));
  298.             return(TRUE);
  299.  
  300.         case WM_COMMAND:                           // the only command is OK
  301.             if(wParam != 1)
  302.                 return(FALSE);
  303.             adv.fRcvFileSelect = IsDlgButtonChecked( hDlg,10)?0:1;
  304.             adv.fSendFileSelect = IsDlgButtonChecked( hDlg,11)?0:1;
  305.             adv.fChecksum = IsDlgButtonChecked( hDlg,21)?1:0;
  306.             adv.fRecLength128 = IsDlgButtonChecked( hDlg,31)?1:0;
  307.             EndDialog( hDlg, TRUE );
  308.             break;
  309.  
  310.         default:
  311.             return( FALSE );
  312.     }
  313.     return( TRUE );
  314. }
  315.  
  316. void RXING()
  317. {
  318. LPSTR lptr;
  319. int i,j;
  320.     if(pd->bCancel)                           // set when user presses cancel on the xfer box
  321.     {
  322.         if(pd->hDlg1)                          // if xfer box is diplayed, show "Aborting by user"
  323.             LastError(4);
  324.         End_It(17);
  325.             return;                             // we have cancel pressed so terminate */
  326.     }
  327.     if( GetTickCount() > pd->xwaittime)       // we timed-out?
  328.     {
  329.         if(pd->hDlg1)
  330.             LastError(1);
  331.         if(pd->bbegin==2)                      // we have not started xfer yet, if retries is OK send another NACK
  332.         {
  333.             if(--pd->retries == 0)
  334.             {
  335.                 End_It(14);
  336.                 return;
  337.             }
  338.             (*pd->WriteCommW) ( (HANDLE)mn->hCid, (LPSTR)"\x15", (int)1);
  339.             pd->xwaittime = GetTickCount()+10000;
  340.             return;
  341.         }
  342.         else if(pd->bbegin == 99)                             // special case, we timed out after sending EOF, and not received NACK
  343.         {
  344.             if(_lwrite( pd->hCommFile, pd->bigbuff, (WORD)(pd->bigptr-pd->bigbuff)) != (WORD)(pd->bigptr-pd->bigbuff))
  345.                 StatusLine(IDS_LASTERROR+19,NULL);                     // Show error writing file
  346.             else
  347.                 StatusLine(IDS_LASTERROR+14,pd->szRcvFile);     // Completed Xfer
  348.             (*pd->WriteCommW) ( (HANDLE)mn->hCid,(LPSTR)"\x06",(int)1);                /* this is ack sent after we sent a nack but got no responce and protocol != batch stuff */
  349.          *pd->aspfxfer = ASP_PROT_SUCCESS;
  350.             (*pd->EndXfer)();                            // leave xfer
  351.             return;
  352.         }
  353.         else
  354.         {
  355.             pd->xwaittime = GetTickCount()+20000;
  356.             if(pd->bbegin > 2)
  357.                 pd->bbegin +=1;
  358.             else
  359.                 pd->bbegin = 3;
  360.             if(pd->bbegin == 5)
  361.                 (*pd->WriteCommW) ( (HANDLE)mn->hCid,(LPSTR)"\x15",(int)1);
  362.             return;
  363.         }
  364.     }
  365.     switch(GetXRecord())
  366.     {
  367.         case IDX_RXING:
  368.             break;
  369.         case IDX_ACK:
  370.             if(((BYTE)pd->rec_no == (BYTE)*(pd->cbuff+1)) && ((BYTE)(*(pd->cbuff+2)+pd->rec_no) == 255))
  371.             {
  372.                 lptr = pd->cbuff;
  373.                 lptr += 3;
  374.                 (*pd->WriteCommW) ( (HANDLE)mn->hCid,(LPSTR)"\x06",(int)1);
  375.                 //▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
  376.                 //  If we're not in a gif state and we want to be
  377.                 //▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
  378.                 if(!mn->gifstate && pd->should_gif)
  379.                 {
  380.                     //▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
  381.                     //  If this is the first block
  382.                     //▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
  383.                     if (pd->runcnt == 0)
  384.                     {
  385.                         AnsiLower((LPSTR)pd->szRcvFile);
  386.                         if(_fstrstr(pd->szRcvFile,".gif"))
  387.                             (*pd->startgif)();
  388.                     }
  389.                 }
  390.                 for(i=0;i<pd->rec_len;i++)
  391.                 {
  392.                     if(mn->gifstate)
  393.                     {
  394.                         j = (*pd->FeedDisplay)((BYTE)*lptr);
  395.                         if(!j)
  396.                         {
  397.                             StatusLine(IDS_LASTERROR+36,pd->szRcvFile);
  398.                             if (!pd->hDlg1 && pd->bdiag)
  399.                             {
  400.                                 (*pd->ShowXferBox)(0);                                         // show xfer box for recieve
  401.                                 SetWindowText( pd->hDlg1,"DLL [XModem]");
  402.                                 SetDlgItemText(pd->hDlg1, ID_FILENAME,AnsiLower(pd->szRcvFile));
  403.                             }
  404.                         }
  405.                     }
  406.                     *pd->bigptr++ = *lptr++;
  407.                 }
  408.                 //▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
  409.                 //  If we're not doing gifs and we
  410.                 //  don't have a status box up
  411.                 //▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
  412.                 if (!mn->gifstate)
  413.                 {
  414.                     if (!pd->hDlg1 && pd->bdiag)
  415.                     {
  416.                         (*pd->ShowXferBox)(0);                                         // show xfer box for recieve
  417.                          SetWindowText( pd->hDlg1,"DLL [XModem]");
  418.                          SetDlgItemText(pd->hDlg1, ID_FILENAME,AnsiLower(pd->szRcvFile));
  419.                     }
  420.                 }
  421.  
  422.                 if(pd->bigptr == (pd->bigbuff+10240))
  423.                 {
  424.                     if(_lwrite( pd->hCommFile, pd->bigbuff, 10240 ) != 10240)
  425.                     {
  426.                         End_It(20);
  427.                         return;
  428.                     }
  429.                     pd->bigptr = pd->bigbuff;
  430.                 }
  431.                 pd->rec_no +=1;
  432.                 pd->rec_no &= 0xff;
  433.                 pd->runcnt += pd->rec_len;
  434.                 if(pd->hDlg1)
  435.                 {
  436.                     wsprintf(szBuffer,"%lu",pd->runcnt);
  437.                     SetDlgItemText(pd->hDlg1,ID_BLKNO, szBuffer);
  438.                     LastError(0);
  439.                 }
  440.                 pd->pcstate = IDX_RXING;
  441.             }
  442.             /* bad record routine */
  443.             else if(((BYTE)(pd->rec_no-1) == (BYTE)*(pd->cbuff+1)) && ( (BYTE)(*(pd->cbuff+2)+pd->rec_no-1) == 255))
  444.             {
  445.                 (*pd->WriteCommW) ( (HANDLE)mn->hCid,(LPSTR)"\x06",(int)1);
  446.                 if(pd->hDlg1)
  447.                 {
  448.                     SetDlgItemInt( pd->hDlg1,ID_ERR,++pd->nackcount,0);
  449.                     if(pd->nackcount > 20)
  450.                         pd->bCancel = 2;
  451.                     LastError(7);
  452.                 }
  453.                 pd->pcstate = IDX_RXING;
  454.             }
  455.             else if(pd->rec_no == 0)
  456.                 End_It(24);
  457.             else
  458.             End_It(19);
  459.             pd->xwaittime = GetTickCount()+20000;
  460.             pd->xcount = 0;
  461.             return;
  462.  
  463.  
  464.         case IDX_NOCHAR:
  465.             if(pd->bCancel)
  466.             {
  467.                 if(pd->hDlg1)
  468.                     LastError(4);
  469.                 End_It(17);
  470.                 return;                              /* we have cancel pressed so terminate */
  471.             }
  472.             pd->xcount = pd->bbegin = 0;
  473.             pd->xwaittime = GetTickCount() + pd->no_char_wait;
  474.             return;
  475.  
  476.         case IDX_EOT:
  477.             if(pd->bbegin != 99)                              // first send a nack to make sure it was a valid EOT*/
  478.             {
  479.                 (*pd->WriteCommW) ( (HANDLE)mn->hCid,(LPSTR)"\x15",(int)1);
  480.                 pd->bbegin = 99;
  481.                 pd->pcstate = IDX_RXING;
  482.                 pd->xwaittime = GetTickCount()+2000;           // just wait 2 seconds for this to happen */
  483.             }
  484.             else
  485.             {
  486.                 if(_lwrite( pd->hCommFile, pd->bigbuff, (WORD)(pd->bigptr-pd->bigbuff)) != (WORD)(pd->bigptr-pd->bigbuff))
  487.                     StatusLine(IDS_LASTERROR+19,NULL);                  /* Show error writing file */
  488.                 else
  489.                     StatusLine(IDS_LASTERROR+14,pd->szRcvFile);                  /* Completed Xfer */
  490.                 (*pd->WriteCommW) ( (HANDLE)mn->hCid,(LPSTR)"\x06",(int)1);
  491.                 *pd->aspfxfer = ASP_PROT_SUCCESS;
  492.              (*pd->EndXfer)();
  493.             }
  494.             return;
  495.  
  496.         default:
  497.             return;
  498.     }
  499. }
  500.  
  501.  
  502.  
  503.  
  504. void WAITACK()
  505. {
  506.     if(pd->bCancel && !pd->Aborting)                      // set so user knows we are pd->Aborting
  507.     {
  508.         pd->Aborting = TRUE;
  509.         *pd->aspfxfer = ASP_PROT_FAIL;               // pointer to aspect file xfer flag
  510.         if(pd->hDlg1)
  511.             LastError(4);
  512.         if(pd->bbegin==1)
  513.             End_It(17);
  514.         return;                              /* we have cancel pressed so terminate */
  515.     }
  516.     if( GetTickCount() > pd->xwaittime )
  517.     {
  518.         if(pd->rec_no != pd->end_record)                  // if they are equal we have good Xfer
  519.         {
  520.             End_It(1);
  521.             return;
  522.         }
  523.         (*pd->EndXfer)();
  524.         return;
  525.     }
  526.     switch(WaitingForAck())
  527.     {
  528.         case IDX_TERMINATE:
  529.             End_It(13);
  530.             return;
  531.  
  532.         case IDX_WAITACK:
  533.             return;
  534.  
  535.         case IDX_ACK:
  536.             if(pd->bCancel)
  537.             {
  538.                 End_It(17);
  539.                 return;
  540.             }
  541.             ymodem_tx();
  542.             pd->xwaittime = GetTickCount()+20000;
  543.     }
  544. }
  545.  
  546.  
  547. void NOCHAR()
  548. {
  549.     if(pd->bCancel)
  550.     {
  551.         *pd->aspfxfer = ASP_PROT_FAIL;               // pointer to aspect file xfer flag
  552.         if(pd->hDlg1)
  553.             LastError(4);
  554.     }
  555.     if(!MoreCharacters())
  556.         pd->xwaittime = GetTickCount() + pd->no_char_wait;
  557.     else if(GetTickCount() > pd->no_char_wait)
  558.     {
  559.         (*pd->WriteCommW) ( (HANDLE)mn->hCid,(LPSTR)"\x15",(int)1);
  560.         pd->xwaittime = GetTickCount()+20000;                // 20 seconds
  561.         pd->pcstate = IDX_RXING;
  562.     }
  563. }
  564.  
  565. // Place a message on PW.EXE statusline
  566. void StatusLine(index,lptr)
  567. WORD index;
  568. LPSTR lptr;
  569. {
  570. char line[128];
  571.  
  572.     LoadString( hInst,index,line,80);         // get resource string
  573.     if(lptr)
  574.         lstrcat(line,lptr);
  575.     (*pd->StatusLineDirect) ( (LPSTR)line);   // call statusline function in PW.EXE
  576. }
  577.  
  578. void LastError(i)
  579. int i;
  580. {
  581. char line[21];
  582.  
  583.     if(pd->hDlg1)
  584.     {
  585.         if(i)
  586.             LoadString( hInst, IDS_LASTERROR+i-1, (LPSTR)line, 20);
  587.         else
  588.             line[0] = 0;
  589.         SetDlgItemText( pd->hDlg1,ID_UARTERR,(LPSTR)line);
  590.     }
  591. }
  592.  
  593. void End_It(i)
  594. int i;
  595. {
  596.     (*pd->WriteCommW) ( (HANDLE)mn->hCid,(LPSTR)"\x18\x18\x18\x18\x18\x18\x18\x18\x08\x08\x08\x08\x08\x08\x08\x08",(int)16);
  597.     StatusLine(IDS_LASTERROR+i-1,NULL);
  598.     *pd->aspfxfer = ASP_PROT_FAIL;               // pointer to aspect file xfer flag
  599.     (*pd->EndXfer)();
  600. }
  601.  
  602.  
  603.  
  604.  
  605. void StartXRecord(dlen, data)
  606. int dlen;
  607. LPSTR data;
  608. {
  609. LPSTR s;
  610. int i,crc;
  611.  
  612.     s=pd->cbuff;
  613.     pd->datalen = dlen;
  614.     pd->rec_no +=1;
  615.     *s++ = 1;
  616.     *s++ = (BYTE)(pd->rec_no);
  617.     *s++ = (BYTE)(255-pd->rec_no);
  618.     (*pd->WriteCommW)( (HANDLE)mn->hCid,(LPSTR)(s-3),(int)3);
  619.  
  620.     crc = 0;
  621.     for(i=0; i<pd->rec_len;i++)
  622.     {
  623.         *s=*data;
  624.         crc += *data++;
  625.         (*pd->WriteCommW)( (HANDLE)mn->hCid,(LPSTR)s++, (int)1);
  626.     }
  627.     *s = LOBYTE(crc);
  628.     (*pd->WriteCommW)( (HANDLE)mn->hCid,(LPSTR)s,(int)1);
  629.     pd->pcstate=IDX_WAITACK;
  630. }
  631.  
  632.  
  633. int WaitingForAck()
  634. {
  635. char recvchar[1];
  636.  
  637.     if( (*pd->GetCommErrorW) ((HANDLE)mn->hCid))
  638.     {
  639.         while(  (*pd->GetCommErrorW) ((HANDLE)mn->hCid));
  640.         (*pd->FlushCommW) ( (HANDLE)mn->hCid, (int)1);                     /* flush recieve que */
  641.         if(pd->hDlg1)
  642.         {
  643.             SetDlgItemInt( pd->hDlg1,ID_ERR,++pd->nackcount,0);
  644.             if(pd->nackcount > 20)
  645.                 pd->bCancel = 2;
  646.             LastError(8);
  647.         }
  648.     }
  649.     else if(mn->comstat.cbInQue >= 1)
  650.     {
  651.         (*pd->ReadCommW) ( (HANDLE)mn->hCid,(LPSTR)recvchar,(int)1);
  652.         if(*recvchar == ACK)
  653.             pd->pcstate = IDX_ACK;
  654.         else if((*recvchar == NAK) && !pd->bbegin)
  655.         {
  656.             if(pd->bCancel)
  657.                 return(pd->pcstate = IDX_ACK);
  658.             (*pd->FlushCommW) ( (HANDLE)mn->hCid,(int)0);
  659.             (*pd->WriteCommW) ( (HANDLE)mn->hCid, (LPSTR)pd->cbuff, (int)pd->xcount);
  660.             if(pd->hDlg1)
  661.             {
  662.                 SetDlgItemInt( pd->hDlg1,ID_ERR,++pd->nackcount,0);
  663.                 if(pd->nackcount > 20)
  664.                     pd->bCancel = 2;
  665.                 LastError(6);
  666.             }
  667.         }
  668.         else if(*recvchar == CANCEL)
  669.         {
  670.             (*pd->FlushCommW) ( (HANDLE)mn->hCid,(int)0);
  671.             pd->pcstate = IDX_TERMINATE;
  672.         }
  673.         else if((*recvchar == NAK) && (pd->bbegin == 1))
  674.         {
  675.             if(pd->bCancel)
  676.                 return(pd->pcstate = IDX_ACK);
  677.             else
  678.                 pd->xcount = 132;
  679.             pd->pcstate = IDX_ACK;
  680.             pd->bbegin = 0;
  681.         }
  682.         else (*pd->FlushCommW) ( (HANDLE)mn->hCid,(int)1);
  683.     }
  684.     return(pd->pcstate);
  685. }
  686.  
  687.  
  688.  
  689. int GetXRecord()
  690. {
  691. short i;
  692. int j,k,l;
  693.  
  694.     if(pd->rcnt>(3*pd->xcount)/4 && pd->xcount)
  695.         k=4;
  696.     else
  697.         k=1;
  698.     for(j=0;j<k;j++)
  699.     {
  700.         l = (*pd->GetCommErrorW) ((HANDLE)mn->hCid);
  701.         if(l)
  702.         {
  703.             while((*pd->GetCommErrorW) ((HANDLE)mn->hCid));
  704.             i = 8;
  705. error_state:
  706.             if(pd->hDlg1)
  707.             {
  708.                 SetDlgItemInt( pd->hDlg1,ID_ERR,++pd->nackcount,0);
  709.                 if(pd->nackcount > 20)
  710.                     pd->bCancel = 2;
  711.                     LastError(i);
  712.             }
  713.             return(pd->pcstate = IDX_NOCHAR);
  714.         }
  715.         if((mn->comstat.cbInQue >= 1) && (pd->xcount == 0))
  716.         {
  717.             if(pd->bbegin && pd->bbegin != 99)
  718.             {
  719.                 pd->bbegin = 0;
  720.                 pd->xwaittime = GetTickCount()+2000;
  721.             }
  722.             (*pd->ReadCommW) ( (HANDLE)mn->hCid,(LPSTR)pd->cbuff,(int)1);
  723.             if(pd->cbuff[0] == 1)
  724.             {
  725.                 pd->rec_len = 128;
  726.                 pd->xcount = 128+3;
  727.             }
  728.             else if(pd->cbuff[0] == EOT)
  729.                 pd->pcstate = IDX_EOT;
  730.             else if(pd->cbuff[0] == CANCEL)
  731.             {
  732.                 StatusLine(IDS_LASTERROR+12,NULL);
  733.                 (*pd->EndXfer) ();
  734.                 return(0);
  735.             }
  736.             else
  737.             {
  738.                 i = 10;
  739.                 goto error_state;
  740.             }
  741.             pd->crc = 0;
  742.             mn->comstat.cbInQue -=1;
  743.             pd->rcnt = 0;
  744.         }
  745.         if(mn->comstat.cbInQue && pd->xcount )
  746.         {
  747.             for(i=0; i<(int)mn->comstat.cbInQue; i++ )
  748.             {
  749.                 (*pd->ReadCommW) ( (HANDLE)mn->hCid,(LPSTR)(pd->cbuff+pd->rcnt+1),(int)1);
  750.                 if(++pd->rcnt<3) continue;
  751.                 else if( pd->rcnt < pd->xcount )
  752.                     pd->crc += pd->cbuff[pd->rcnt];
  753.                 if(pd->rcnt != pd->xcount) continue;
  754.                 if((BYTE)*(pd->cbuff+pd->xcount)==LOBYTE(pd->crc))
  755.                     pd->pcstate = IDX_ACK;
  756.                 else
  757.                 {
  758.                         i=2; goto error_state;
  759.                 }
  760.             }
  761.         }
  762.   }
  763.   return(pd->pcstate);
  764. }
  765.  
  766.  
  767. BOOL MoreCharacters()
  768. {
  769.     (*pd->GetCommErrorW) ((HANDLE)mn->hCid);
  770.     if( mn->comstat.cbInQue != 0)
  771.     {
  772.         (*pd->FlushCommW) ( (HANDLE)mn->hCid,(int)1);
  773.         return(FALSE);
  774.     }
  775.     else return(TRUE);
  776. }
  777.  
  778. void ymodem_tx()
  779. {
  780. int nbytes;
  781. LPSTR lptr;
  782. int i;
  783.  
  784.     LastError(0);
  785. go_again:
  786.     if(pd->rec_no == pd->end_record )                     // we are at end of file we transmitt a EOT! wait for it to be acked
  787.     {
  788.         if(pd->bpos)
  789.         {
  790.             (*pd->WriteCommW) ( (HANDLE)mn->hCid,(LPSTR)"\x4",(int)1);           // send EOF and be ready to re-tx if nack
  791.             pd->xcount = 1;
  792.             *pd->cbuff = '\x4';
  793.             pd->pcstate = IDX_WAITACK;
  794.             pd->bpos = 0;
  795.             return;
  796.         }
  797.         else
  798.         {
  799.             StatusLine(IDS_LASTERROR+14,pd->szRcvFile);     // Completed Xfer
  800.             (*pd->EndXfer)();
  801.             return;
  802.         }
  803.     }
  804.     if( pd->bigptr == (pd->bigbuff+10240) )
  805.     {
  806.         nbytes = _lread( pd->hCommFile, pd->bigbuff, 10240);
  807.         if(!nbytes)
  808.         {
  809.             pd->end_record = pd->rec_no = pd->bpos = 1;         // this is to let the if statements pass through */
  810.             goto go_again;
  811.         }
  812.         pd->bigptr = pd->bigbuff;
  813.         if(nbytes != 10240)
  814.         {
  815.             pd->end_record = pd->rec_no+(int)(nbytes/pd->rec_len);
  816.             if(nbytes%pd->rec_len)
  817.                 pd->end_record += 1;
  818.             lptr= pd->bigbuff+nbytes;
  819.             for(i=0;i< (int)(10240L-nbytes);i++)
  820.                 *lptr++ = 0;
  821.             pd->bpos = 1;
  822.         }
  823.         else
  824.             pd->end_record = pd->rec_no - 5;
  825.     }
  826.     StartXRecord(pd->rec_len, pd->bigptr);
  827.     pd->bigptr += pd->rec_len;
  828.     if(pd->hDlg1)
  829.     {
  830.         pd->runcnt += pd->rec_len;
  831.         wsprintf( szBuffer,"%lu",pd->runcnt);
  832.         SetDlgItemText(pd->hDlg1,ID_BLKNO, szBuffer);
  833.         InvalidateRect(GetDlgItem(pd->hDlg1,ID_PERCENT),NULL,FALSE);
  834.         (*pd->TimeToGo) ();
  835.     }
  836.     pd->pcstate = IDX_WAITACK;
  837. }
  838.  
  839.  
  840. BOOL FileRxTX(int send, LPSTR ptr)
  841. {
  842. OFSTRUCT ofs;
  843.  
  844.     lstrcpy(szBuffer,pd->szTempDir);
  845.     lstrcat(szBuffer,"\\");
  846.     lstrcat((LPSTR)szBuffer,ptr);
  847.     lstrcpy((LPSTR)pd->szRcvFile,ptr);
  848.     if(send==0)
  849.     {
  850.         if( (pd->hCommFile = OpenFile( (LPSTR)szBuffer, &ofs, OF_CREATE | OF_WRITE )) == -1)
  851.         {
  852.             StatusLine( IDS_LASTERROR+26,szBuffer);
  853.             *pd->aspfxfer=ASP_PROT_FAIL;
  854.             return( FALSE);
  855.         }
  856.         return(TRUE);
  857.     }
  858.     if( (pd->hCommFile = OpenFile( (LPSTR)szBuffer, &ofs, OF_READ )) == -1)
  859.     {
  860.         StatusLine( IDS_LASTERROR+24,szBuffer);
  861.         *pd->aspfxfer=ASP_PROT_FAIL;
  862.         return( FALSE);
  863.     }
  864.     pd->flen = filelength(pd->hCommFile);
  865.     pd->fdate = getfdate(pd->hCommFile);
  866.     pd->fftime = getftime(pd->hCommFile);
  867.     return(TRUE);
  868. }
  869.